from Axon.Component import component
from Axon.Component import makeOutbox
import Axon
_cat = Axon.CoordinatingAssistantTracker
from Kamaelia.Chassis.Graphline import Graphline
from Kamaelia.Chassis.ConnectedServer import SimpleServer
from Kamaelia.Util.Console import ConsoleEchoer
import struct
import pickle
import Command
    
class Packetizer(component):
    """ Component that packetize/unpacketize data (in form of (type,data,)) and data chunks
    readInbox (data) -> (packet) readOutbox
    writeOutbox (data) <- (packet) writeInbox  
    
    """
    
    Inboxes = {"readInbox" : "","writeInbox" : "","control" : ""}
    Outboxes = {"writeOutbox" : "","readOutbox" : "","signal" : ""}
    
    def __init__(self):
        self.__super.__init__() # Must always happen!
        self.packetBuffer = ""
                
    def main(self):
        while True:
            yield 1        
            # Data to depacetize?
            if self.dataReady("readInbox"):
                self.packetBuffer = self.packetBuffer + self.recv("readInbox")                 
                while(len(self.packetBuffer) >= 8):                                    
                    # Get packet size
                    packetSize = struct.unpack("!I", self.packetBuffer[0:4])[0]

                    if(len(self.packetBuffer) -8 >= packetSize):                    
                        # Get packet type and send unpacked data
                        packetType = struct.unpack("!I", self.packetBuffer[4:8])[0]
                        self.send((packetType,self.packetBuffer[8:packetSize+8]),"readOutbox")
                        self.packetBuffer= self.packetBuffer[packetSize+8:]
                                                
            # Data to pacetize?                       
            if self.dataReady("writeInbox"):
                packet = self.recv("writeInbox")                
                data = struct.pack("!II", len(packet[1]),packet[0])
                data = data + packet[1]                
                self.send(data,"writeOutbox")
                
            if self.shutdown():
                return
                        

    def shutdown(self):
        if self.dataReady("control"):
            msg = self.recv("control")
            if(isinstance(msg, Axon.Ipc.producerFinished)):
                self.send(msg,"signal")
                return True
            return False 
        
class Commandizer(component):
    """ Component that pickle and unpickle data
    readInbox (packet) -> (object) readOutbox
    writeOutbox (packet) <- (object) writeInbox  """
    
    Inboxes = {"readInbox" : "","writeInbox" : "","control" : ""}
    Outboxes = {"readOutbox" : "","writeOutbox" : "","signal" : ""}
    
    def __init__(self):
        self.__super.__init__() # Must always happen!
        
    def main(self):
        while True:
            yield 1
        
            # Write?
            if self.dataReady("writeInbox"):
                data = self.recv("writeInbox")
                print "Comandizing:" + str(data)
                self.send((0,pickle.dumps(data)),"writeOutbox")
                                                
            # Data to data -> outbox                       
            if self.dataReady("readInbox"):
                packet = self.recv("readInbox")
                data = pickle.loads(packet[1])
                print "Decomandizing:" + str(data)                                
                self.send(data,"readOutbox")                
                                
            if self.shutdown():
                return
            
    def shutdown(self):
        if self.dataReady("control"):
            msg = self.recv("control")
            if(isinstance(msg, Axon.Ipc.producerFinished)):
                self.send(msg,"signal")
                return True
            return False 

class PlayerPrefix(component):
    """ Component that prefix incoming touple with
        playerId
    """
    
    Inboxes = {"readInbox" : "",            
               "writeInbox" : "",
               "control" : ""}
    Outboxes = {"readOutbox" : "",
                "writeOutbox" : "",
                "signal" : "",}
    
    def __init__(self,playerId):
        self.__super.__init__() # Must always happen!
        self.playerId = playerId
        
    def main(self):
        # Send CREATE_PLAYER command
        self.send((self.playerId,Command.COMMAND_INIT_PLAYER,(self,"writeInbox")),"readOutbox")
        
        while not self.shutdown():
            yield 1
        
            # Data to inbox -> data
            while self.dataReady("readInbox"):
                data = self.recv("readInbox")
                self.send((self.playerId,) + data,"readOutbox")
            
            while self.dataReady("writeInbox"):
                self.send(self.recv("writeInbox"),"writeOutbox")
                        
    def shutdown(self):
        if self.dataReady("control"):
            msg = self.recv("control")
            if(isinstance(msg, Axon.Ipc.producerFinished)):
                self.send(msg,"signal")
                return True
            return False 


class CreatePlayerHandler(object):
    def __init__(self):
        self.playerIdCounter = 1
        
    def __call__(self,*argl):
        id = self.playerIdCounter
        self.playerIdCounter+=1
        print "Generating player graphline with id " + str(id)
                
        proto = Graphline(PACKETIZER  = Packetizer(),
                          COMMANDIZER = Commandizer(),
                          PLAYER_PREFIX = PlayerPrefix(id),    
                          linkages = {
                                      # socket -> PACKETIZER -> COMANDIZER -> PLAYER_PREFIXER -> commandOutbox                                      
                                      ("self",     "inbox")       : ("PACKETIZER", "readInbox"),
                                      ("PACKETIZER","readOutbox") : ("COMMANDIZER", "readInbox"),
                                      ("COMMANDIZER", "readOutbox") : ("PLAYER_PREFIX","readInbox"),
                                      ("PLAYER_PREFIX","readOutbox") : ("self","commandOutbox"),
                                            
                                      # socket <- PACKETIZER <- COMANDIZER <- PLAYER_PREFIXER <- commandInbox                                
                                      ("PACKETIZER","writeOutbox") : ("", "outbox"),
                                      ("COMMANDIZER", "writeOutbox") : ("PACKETIZER","writeInbox"),
                                      ("PLAYER_PREFIX", "writeOutbox") : ("COMMANDIZER","writeInbox"),                                                                                                                
                                      ("self","commandInbox") : ("PLAYER_PREFIX","writeInbox"),                                      
                                     }
                          )
        return proto
